package com.authine.cloudpivot.ext.utils;

import com.alibaba.cola.dto.SingleResponse;
import com.authine.cloudpivot.ext.Enum.BillType;
import com.authine.cloudpivot.ext.Enum.InvoiceBusinessType;
import com.authine.cloudpivot.ext.Enum.InvoiceType;
import com.authine.cloudpivot.ext.constants.AppConst;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.constants.PlatformConst;
import com.authine.cloudpivot.ext.dto.BillDto;
import com.authine.cloudpivot.ext.dto.BillFeeDto;
import com.authine.cloudpivot.ext.dto.kingDee.request.KingDeeInvoiceApply;
import com.authine.cloudpivot.ext.dto.kingDee.request.KingDeeRedInvoiceApply;
import com.authine.cloudpivot.ext.dto.model.bill.Bill;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceApply;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceDetailBill;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceExtendsAttr;
import com.authine.cloudpivot.ext.dto.voucher.RecordVoucher;
import com.authine.cloudpivot.ext.enums.kingdee.KingDeeInvoiceApplyTypeEnum;
import com.authine.cloudpivot.ext.enums.order.transfer.OrderType;
import com.authine.cloudpivot.ext.service.RecordVoucherService;
import com.authine.mvp.app.launcher.domain.SelectorFormat;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.gateway.bo.BOValidatedAndFormatService;
import com.authine.mvp.app.launcher.utils.JsonParseObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Select;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: liwei
 * @DateTime: 2021/7/28
 * @Description: TODO
 */
@Slf4j
public class RecordingVoucherPmUtil {

    private final BOValidatedAndFormatService boValidatedAndFormatService = ApplicationContextUtils.getBean(BOValidatedAndFormatService.class);

    public RecordVoucherService recordVoucherService = new RecordVoucherService();


    /**
     * 开票 修改发票 生成凭证
     *
     * @param invoiceApply
     * @param kingdeeCode
     * @return
     */
    public KingDeeInvoiceApply createOrUpdateInvoiceVoucher(InvoiceApply invoiceApply, String kingdeeCode) {
        log.info("createOrUpdateInvoiceVoucher  request:{}", invoiceApply);

        Assert.notNull(invoiceApply, "入参 发票申请单 不能为空");

        Map<String, Object> invoiceApplyMap = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).eq("id", invoiceApply.getId())
                .selectField("*").queryForMap();

        Assert.notNull(invoiceApplyMap, "查询 发票申请单数据 不能为空");


        List<Map<String, Object>> invoiceDetailList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_DETAIL).eq("invoice_apply_id", invoiceApply.getId())
                .selectField("*").queryForList();

        Assert.isTrue(null != invoiceDetailList && invoiceDetailList.size() > 0, "查询 发票申请单数据 不能为空");

        InvoiceBusinessType invoiceBusinessType = InvoiceBusinessType.valueOf(String.valueOf(invoiceApplyMap.get("business_type")));
        //判断发票是否为 销售货物蓝字发票
        if (!PlatformConst.PLATFORM_ORGANIZATION_IDS.contains(invoiceApply.getSale_organization_id()) || InvoiceBusinessType.Product != invoiceBusinessType) {

            return null;
        }

        // 获取第一个税率 云枢版本 冗余了开票税率字段
        BigDecimal taxRate = new BigDecimal(String.valueOf(invoiceApplyMap.get("tax_rate")));

        // purchase_organization_id 获取采购方组织信息
        List<SelectorFormat> purchaseSelector = new ArrayList<>();
        if (null != invoiceApplyMap.get("purchase_organization_id")) {
            purchaseSelector = JsonParseObject.parseObject(String.valueOf(invoiceApplyMap.get("purchase_organization_id")), SelectorFormat.class);
        }
        log.info("purchaseSelector :{}", purchaseSelector);

        Map<String, Object> purchaseOrg = JdbcTemplateUtils.builder(AppConst.SYSTEM_MANAGEMENT, ModelConst.T_ORGANIZATION)
                .eq("id", purchaseSelector.get(0).getId()).selectField("*").queryForMap();

        String parentName = "";
        if (null != purchaseOrg.get("parent_id")) {
            parentName = String.valueOf(purchaseOrg.get("parent_name"));
        }

        //获取 当前会话 部门信息
        SelectorFormat currentDepartment = boValidatedAndFormatService.getCurrentDepartment();

        Map<String, Object> currentDepart = JdbcTemplateUtils.builder(AppConst.SYSTEM_MANAGEMENT, ModelConst.T_DEPARTMENT)
                .eq("id", currentDepartment.getId()).selectField("*").queryForMap();

        Set<String> tradeIdList = invoiceDetailList.stream().map(e -> String.valueOf(e.get("trade_id"))).collect(Collectors.toSet());

        List<Map<String, Object>> tradeList = JdbcTemplateUtils.builder(ModelConst.T_TRADE).in("id", tradeIdList)
                .selectField("*").queryForList();

        Assert.isTrue(null != tradeList && tradeList.size() > 0, "查询 交易数据实例 不能为空");


        //是否为转采订单 集合
        Set<Boolean> transferPurchase = tradeList.stream().map(e -> Boolean.valueOf(String.valueOf(e.get("transfer_purchase")))).collect(Collectors.toSet());

        //既有转采 又有非转采
        Boolean isTransferPurchaseAndPlatform = transferPurchase.size() > 1 && transferPurchase.contains(true);

        //转采
        Boolean isTransfer = transferPurchase.contains(true);

        //转采不含税采购金额
        BigDecimal purchaseTransferPurchasePretaxAmount = BigDecimal.ZERO;
        //转采不含税销售金额
        BigDecimal saleTransferPurchasePretaxAmount = BigDecimal.ZERO;
        //平台不含税销售金额
        BigDecimal platformDoesNotIncludeTaxSalesAmount = BigDecimal.ZERO;

        //todo 通过SQL 过滤 此处SQL待完善

        String invoiceApplyTable = JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_APPLY);
        String invoiceDetailTable = JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_DETAIL);
        String tradeTable = JdbcTemplateUtils.getTableName(ModelConst.T_TRADE);


        StringBuilder builder = new StringBuilder();
        builder.append("SELECT  iid.invoice_apply_id  FROM ");
        builder.append(invoiceDetailTable);
        builder.append(" AS iid LEFT JOIN ");
        builder.append(invoiceApplyTable);
        builder.append(" AS iia ON iia.id = iid.invoice_apply_id LEFT JOIN ");
        builder.append(tradeTable);
        builder.append(" AS it ON it.id = iid.trade_id ");
        builder.append(" WHERE iia.business_type = 'Product' AND iia.statuss = 'Done' AND iid.trade_id IN ( :tradeIds )  AND iid.offset_quantity != iid.quantity ");
        String sqlStr = builder.toString();

        Map<String, Object> param = new HashMap<>();
        param.put("tradeIds", tradeIdList);

        List<Map<String, Object>> fitData = JdbcTemplateUtils.queryForList(sqlStr, param);

        Assert.isTrue(null != fitData && fitData.size() > 0, "未找到  符合状态的发票详情数据 ");

        Set<String> invoiceApplyIds = fitData.stream().map(e -> String.valueOf(e.get("invoice_apply_id"))).collect(Collectors.toSet());

        Map<String, List<Map<String, Object>>> tradeGroup = new HashMap<>();
        //没有已开票数量
        if (!(null == invoiceApplyIds || invoiceApplyIds.isEmpty())) {
            //排除当前正在开票的数据
            invoiceApplyIds = invoiceApplyIds.stream().filter(e -> !e.equals(invoiceApply.getId())).collect(Collectors.toSet());
            //获取已生成凭证的业务id
            SingleResponse<List<RecordVoucher>> response = recordVoucherService.getVoucherByBusinessIds(invoiceApplyIds);

            if (response.isSuccess() && response.getData() != null && !response.getData().isEmpty()) {

                List<String> businessIdList = response.getData().stream().map(RecordVoucher::getBusiness_id).collect(Collectors.toList());
                //从待收和已开票ID列表获取已生成凭证的ID列表
                invoiceApplyIds = invoiceApplyIds.stream().filter(e -> businessIdList.contains(e)).collect(Collectors.toSet());
                //根据当前交易记录和已生成凭证的发票ID列表获取对应的发票详情列表
                List<Map<String, Object>> invoiceDetailList2 = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_DETAIL).in("invoice_apply_id", invoiceApplyIds).in("trade_id", tradeIdList)
                        .selectField("*").queryForList();

                if (!(null == invoiceDetailList2 || invoiceDetailList2.isEmpty())) {
                    //根据交易记录 id 分组
                    tradeGroup = invoiceDetailList2.stream().collect(Collectors.groupingBy(e -> String.valueOf(e.get("trade_id"))));
                }
            }
        }

        Map<Object, Map<String, Object>> tradeMap = tradeList.stream().collect(Collectors.toMap(e -> e.get("id"), e -> e));
        //遍历详情列表
        for (Map<String, Object> invoiceDetail : invoiceDetailList) {
            String tradeId = String.valueOf(invoiceDetail.get("trade_id"));
            Map<String, Object> trade = tradeMap.get(tradeId);

            //是否为转采 true 为转采 false | null 均为平台
            Boolean isTransfer2 = trade.get("transfer_purchase") == null ? null : Boolean.valueOf(String.valueOf(trade.get("transfer_purchase")));


            //转采
            if (null != isTransfer2 && isTransfer2) {

                saleTransferPurchasePretaxAmount = new BigDecimal(String.valueOf(invoiceDetail.get("invoiceDetail"))).add(saleTransferPurchasePretaxAmount);

                BigDecimal doneInvoiceNum = BigDecimal.ZERO;
                //获取 交易对应的 发票明细列表
                List<Map<String, Object>> detailList = tradeGroup.get(tradeId);
                if (!(null == detailList || detailList.isEmpty())) {

                    for (Map<String, Object> detailDone : detailList) {

                        BigDecimal quantity = new BigDecimal(String.valueOf(detailDone.get("quantity")));
                        BigDecimal offsetQuantity = new BigDecimal(String.valueOf(detailDone.get("offset_quantity")));
                        BigDecimal num = quantity.subtract(offsetQuantity);

                        doneInvoiceNum = num.add(doneInvoiceNum);

                    }
                }

                //转采 根据采购批次分组
                //待付款 2，部分付款 3，已付款 4
                // 会员订单商品表 t_member_purchase_order_goods
                // 会员订单表 t_member_purchase_order
                // 转采订单商品表 t_transfer_order_goods
                // 转采订单表 t_transfer_order
                String memberOderTableName = JdbcTemplateUtils.getTableName(AppConst.ORDER_CENTER, ModelConst.T_MEMBER_PURCHASE_ORDER);
                String memberOderGoodsTableName = JdbcTemplateUtils.getTableName(ModelConst.T_MEMBER_PURCHASE_ORDER_GOODS);
                String transferOrderTableName = JdbcTemplateUtils.getTableName(AppConst.ORDER_CENTER, ModelConst.T_TRANSFER_ORDER);
                String transferOrderGoodsTableName = JdbcTemplateUtils.getTableName(AppConst.ORDER_CENTER, ModelConst.T_TRANSFER_ORDER_GOODS);

                log.info("数据库名称  memberOderTableName:{},memberOderGoodsTableName:{},transferOrderTableName:{},transferOrderGoodsTableName:{}", memberOderTableName, memberOderGoodsTableName, transferOrderTableName, transferOrderGoodsTableName);

                StringBuilder sb = new StringBuilder();
                sb.append("SELECT  g.*  FROM ");
                sb.append(memberOderGoodsTableName);
                sb.append(" AS g LEFT JOIN ");
                sb.append(memberOderTableName);
                sb.append(" AS m ON m.id = g.member_purchase_order_id LEFT JOIN ");
                sb.append(transferOrderGoodsTableName);
                sb.append(" AS t ON t.id = g.transfer_order_goods_id LEFT JOIN ");
                sb.append(transferOrderTableName);
                sb.append(" AS o ON o.id = t.transfer_order_id WHERE AND o.order_type IS NULL AND m.is_rp <> TRUE AND m.member_purchase_order_status IN ( 2, 3, 4 ) AND t.cloud_order_goods_id = :orderGoodsId  ORDER BY g.purchase_batch ASC ");
                String sql = sb.toString();
                log.info("根据采购批次分组 执行SQL :{}", sql);
                Map<String, Object> paramM = new HashMap<>();
                paramM.put("orderGoodsId", trade.get("order_goods_id"));
                List<Map<String, Object>> memberGoodsList = JdbcTemplateUtils.queryForList(sql, paramM);

                Assert.isTrue(null != memberGoodsList && memberGoodsList.size() > 0, "未找到  转采订单相关数据 ");

                //采购数量
                BigDecimal purchaseNum = BigDecimal.ZERO;
                //成本金额
                BigDecimal costAmount = BigDecimal.ZERO;
                //单次循环采购数量
                BigDecimal loopNum = BigDecimal.ZERO;

                BigDecimal quantityReceived = new BigDecimal(String.valueOf(invoiceDetail.get("quantity")));

                BigDecimal receivedNum = doneInvoiceNum;

                for (Map<String, Object> memberGoods : memberGoodsList) {

                    BigDecimal num = new BigDecimal(String.valueOf(memberGoods.get("num")));
                    purchaseNum = purchaseNum.add(num);

                    if (receivedNum.compareTo(loopNum = loopNum.add(num)) == 1) {
                        continue;
                    }

                    BigDecimal residueNum = loopNum.subtract(receivedNum);

                    if (quantityReceived.compareTo(residueNum) <= 0) {

                        BigDecimal prePrice = new BigDecimal(String.valueOf(memberGoods.get("pre_price")));
                        costAmount = quantityReceived.multiply(prePrice).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP).add(costAmount);
                        receivedNum = residueNum.add(receivedNum);
                        quantityReceived = quantityReceived.subtract(residueNum);
                    }
                }

                //转采采购金额 先进先出
                purchaseTransferPurchasePretaxAmount = purchaseTransferPurchasePretaxAmount.add(costAmount);
            }

            if (null == isTransfer2 || !isTransfer2) {
                platformDoesNotIncludeTaxSalesAmount = platformDoesNotIncludeTaxSalesAmount.add(new BigDecimal(String.valueOf(invoiceDetail.get("amount"))));
            }

        }

        List<Map<String, Object>> billList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_DETAIL_BILL).eq("invoice_apply_id", invoiceApply.getId()).selectField("*").queryForList();

        Assert.isTrue(null != billList && billList.size() > 0, "未找到  账单数据 ");


        SelectorFormat purchaseOrganizationId = invoiceApply.getPurchase_organization_id();
        SelectorFormat saleOrganizationId = invoiceApply.getSale_organization_id();
        String accountName = PlatformConst.getPlatformOrganizationName(purchaseOrganizationId.getId(), saleOrganizationId.getId());

        KingDeeInvoiceApply kingDeeInvoiceApply = new KingDeeInvoiceApply();
        kingDeeInvoiceApply.setId(invoiceApply.getId());
        kingDeeInvoiceApply.setName(invoiceApply.getPurchase_name());
        kingDeeInvoiceApply.setNumber(invoiceApply.getNumber());
        kingDeeInvoiceApply.setAmount(invoiceApply.getTotal());
        kingDeeInvoiceApply.setPretaxAmount(invoiceApply.getPrice_amount());
        kingDeeInvoiceApply.setTaxPayable(invoiceApply.getTax_amount());
        kingDeeInvoiceApply.setTaxRate(taxRate);
        kingDeeInvoiceApply.setType(convertInvoiceType(invoiceApply.getType()));
        kingDeeInvoiceApply.setInvoiceTime(invoiceApply.getDate());
        kingDeeInvoiceApply.setPurchaseTransferPurchasePretaxAmount(purchaseTransferPurchasePretaxAmount);
        kingDeeInvoiceApply.setSaleTransferPurchasePretaxAmount(saleTransferPurchasePretaxAmount);
        kingDeeInvoiceApply.setPlatformDoesNotIncludeTaxSalesAmount(platformDoesNotIncludeTaxSalesAmount);
        kingDeeInvoiceApply.setIsTransferPurchaseAndPlatform(isTransferPurchaseAndPlatform);
        kingDeeInvoiceApply.setIsTransfer(isTransfer);
        kingDeeInvoiceApply.setOrgId(purchaseSelector.get(0).getId());
        kingDeeInvoiceApply.setParentName(parentName);
        kingDeeInvoiceApply.setCompanyName(String.valueOf(purchaseOrg.get("name")));
        kingDeeInvoiceApply.setArchitectureType(null);
        kingDeeInvoiceApply.setKingdeeCode(kingdeeCode);
        kingDeeInvoiceApply.setDepartmentNumber(String.valueOf(currentDepart.get("number")));
        kingDeeInvoiceApply.setContractInvoiceType(invoiceApply.getTrade_order_type().equals(OrderType.Contract));
        kingDeeInvoiceApply.setInvoiceDetailSize(billList.size());
        kingDeeInvoiceApply.setAccountName(accountName);

        log.info("createOrUpdateInvoiceVoucher  End of  logic processing <<<");
        return kingDeeInvoiceApply;
    }


    /**
     * 开红色发票 修改红色发票
     *
     * @param invoiceApply
     * @param kingdeeCode
     * @return
     */
    public KingDeeRedInvoiceApply createOrUpdateRedInvoiceVoucher(InvoiceApply invoiceApply, String kingdeeCode) {
        log.info("createOrUpdateRedInvoiceVoucher  request:{}", invoiceApply);

        Map<String, Object> invoiceApplyData = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).eq("id", invoiceApply.getId())
                .selectField("*").queryForMap();

        Assert.notNull(invoiceApplyData, "开票申请单不能为空");

        InvoiceExtendsAttr extendsAttr = InvoiceExtendsAttr.conversion(invoiceApply.getExtends_attr()).orElse(new InvoiceExtendsAttr());

        List<Map<String, Object>> invoiceDetailList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_DETAIL).eq("invoice_apply_id", invoiceApply.getId())
                .selectField("*").queryForList();

        Assert.isTrue(null != invoiceDetailList && invoiceDetailList.size() > 0, "开票申请单明细不能为空");

        Set<String> tradeIdList = invoiceDetailList.stream().map(e -> String.valueOf(e.get("trade_id"))).collect(Collectors.toSet());

        List<Map<String, Object>> tradeList = JdbcTemplateUtils.builder(ModelConst.T_TRADE).in("id", tradeIdList)
                .selectField("*").queryForList();

        Assert.isTrue(null != tradeList && tradeList.size() > 0, "开票申请单明细 对应交易信息 不能为空");

        //是否为转采订单 集合
        Set<Boolean> transferPurchase = tradeList.stream().map(e -> Boolean.valueOf(String.valueOf(e.get("transfer_purchase")))).collect(Collectors.toSet());

        //转采不含税采购金额
        BigDecimal purchaseTransferPurchasePretaxAmount = BigDecimal.ZERO;
        //转采不含税销售金额
        BigDecimal saleTransferPurchasePretaxAmount = BigDecimal.ZERO;
        //平台不含税销售金额
        BigDecimal platformDoesNotIncludeTaxSalesAmount = BigDecimal.ZERO;

        //todo 根据 开票申请单获取对应 对应条件 开票明细数据 集合
        String invoiceApplyTable = JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_APPLY);
        String invoiceDetailTable = JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_DETAIL);
        String tradeTable = JdbcTemplateUtils.getTableName(ModelConst.T_TRADE);

        StringBuilder builder = new StringBuilder();
        builder.append("SELECT  iid.*  FROM ");
        builder.append(invoiceDetailTable);
        builder.append(" AS iid LEFT JOIN ");
        builder.append(invoiceApplyTable);
        builder.append(" AS iia ON iia.id = iid.invoice_apply_id LEFT JOIN ");
        builder.append(tradeTable);
        builder.append(" AS it ON it.id = iid.trade_id ");
        builder.append(" WHERE iia.business_type = 'Product' AND iia.statuss != 'Cancel' AND iid.trade_id IN ( :tradeIds )  AND iid.offset_quantity != iid.quantity ");
        String sqlStr = builder.toString();

        Map<String, Object> param = new HashMap<>();
        param.put("tradeIds", tradeIdList);

        List<Map<String, Object>> invoiceDetailList2 = JdbcTemplateUtils.queryForList(sqlStr, param);

        Assert.isTrue(null != invoiceDetailList2 && invoiceDetailList2.size() > 0, "未找到 符合条件的开票明细数据!!! ");

        Set<String> redInvoiceIds = invoiceDetailList2.stream().map(e -> String.valueOf(e.get("invoice_apply_id"))).collect(Collectors.toSet());

        Map<String, List<Map<String, Object>>> groupMap = null;
        //没有已开票数量
        if (CollectionUtils.isEmpty(redInvoiceIds)) {
            //排除当前正在开票数据
            redInvoiceIds = redInvoiceIds.stream().filter(e -> !e.equals(invoiceApply.getId())).collect(Collectors.toSet());

            //获取已生成凭证的数据
            SingleResponse<List<RecordVoucher>> response = recordVoucherService.getVoucherByBusinessIds(redInvoiceIds);
            //如果返回NULL或者为空，说明这批业务编号没有生成凭证
            if (response.isSuccess() && response.getData() != null && !response.getData().isEmpty()) {

                List<String> businessIdList = response.getData().stream().map(RecordVoucher::getBusiness_id).collect(Collectors.toList());
                //从待收和已开票ID列表获取已生成凭证的明细列表
                List<Map<String, Object>> invoiceDetailList3 = invoiceDetailList2.stream().filter(e -> businessIdList.contains(String.valueOf(e.get("invoice_apply_id")))).collect(Collectors.toList());

                //根据当前交易记录和已生成凭证的发票ID列表获取对应的发票详情列表
                //根据交易记录ID分组
                groupMap = invoiceDetailList3.stream().collect(Collectors.groupingBy(e -> String.valueOf(e.get("trade_id"))));

            }

        }

        Map<Object, Map<String, Object>> tradeMap = tradeList.stream().collect(Collectors.toMap(e -> e.get("id"), e -> e));

        Set<String> vendorOrderIdList = new HashSet<>();

        for (Map<String, Object> invoiceDetail : invoiceDetailList) {

            String tradeId = String.valueOf(invoiceDetail.get("trade_id"));
            Map<String, Object> trade = tradeMap.get(tradeId);

            //是否为转采 true 为转采 false | null 均为平台
            Boolean isTransfer = trade.get("transfer_purchase") == null ? null : Boolean.valueOf(String.valueOf(trade.get("transfer_purchase")));

            BigDecimal amount = new BigDecimal(String.valueOf(invoiceDetail.get("amount")));

            if (null != isTransfer && isTransfer) {
                saleTransferPurchasePretaxAmount = amount.add(saleTransferPurchasePretaxAmount);

                BigDecimal doneInvoiceNum = BigDecimal.ZERO;
                if (!CollectionUtils.isEmpty(groupMap)) {
                    List<Map<String, Object>> invoiceDetailList4 = groupMap.get(tradeId);

                    for (Map<String, Object> invoiceDetail2 : invoiceDetailList4) {

                        BigDecimal quantity = new BigDecimal(String.valueOf(invoiceDetail2.get("quantity")));
                        BigDecimal offsetQuantity = new BigDecimal(String.valueOf(invoiceDetail2.get("offset_quantity")));
                        BigDecimal num = quantity.subtract(offsetQuantity);

                        doneInvoiceNum = num.add(doneInvoiceNum);

                    }
                }
                //开红票也按照 先进先出 转采开红票成本转回
                //转采 根据采购批次分组
                //待付款 2，部分付款 3，已付款 4
                // 会员订单商品表 t_member_purchase_order_goods
                // 会员订单表 t_member_purchase_order
                // 转采订单商品表 t_transfer_order_goods
                // 转采订单表 t_transfer_order
                String memberOderTableName = JdbcTemplateUtils.getTableName(AppConst.ORDER_CENTER, ModelConst.T_MEMBER_PURCHASE_ORDER);
                String memberOderGoodsTableName = JdbcTemplateUtils.getTableName(ModelConst.T_MEMBER_PURCHASE_ORDER_GOODS);
                String transferOrderTableName = JdbcTemplateUtils.getTableName(AppConst.ORDER_CENTER, ModelConst.T_TRANSFER_ORDER);
                String transferOrderGoodsTableName = JdbcTemplateUtils.getTableName(AppConst.ORDER_CENTER, ModelConst.T_TRANSFER_ORDER_GOODS);

                log.info("数据库名称  memberOderTableName:{},memberOderGoodsTableName:{},transferOrderTableName:{},transferOrderGoodsTableName:{}", memberOderTableName, memberOderGoodsTableName, transferOrderTableName, transferOrderGoodsTableName);

                StringBuilder sb = new StringBuilder();
                sb.append("SELECT  g.*  FROM ");
                sb.append(memberOderGoodsTableName);
                sb.append(" AS g LEFT JOIN ");
                sb.append(memberOderTableName);
                sb.append(" AS m ON m.id = g.member_purchase_order_id LEFT JOIN ");
                sb.append(transferOrderGoodsTableName);
                sb.append(" AS t ON t.id = g.transfer_order_goods_id LEFT JOIN ");
                sb.append(transferOrderTableName);
                sb.append(" AS o ON o.id = t.transfer_order_id WHERE AND o.order_type IS NULL AND m.is_rp <> TRUE AND m.member_purchase_order_status IN ( 2, 3, 4 ) AND t.cloud_order_goods_id = :orderGoodsId  ORDER BY g.purchase_batch ASC ");
                String sql = sb.toString();
                log.info("根据采购批次分组 执行SQL :{}", sql);
                Map<String, Object> paramM = new HashMap<>();
                paramM.put("orderGoodsId", trade.get("order_goods_id"));
                List<Map<String, Object>> memberGoodsList = JdbcTemplateUtils.queryForList(sql, paramM);

                Assert.isTrue(null != memberGoodsList && memberGoodsList.size() > 0, "未找到 转采订单相关数据!!! ");

                //采购数量
                BigDecimal purchaseNum = BigDecimal.ZERO;
                //成本金额
                BigDecimal costAmount = BigDecimal.ZERO;
                //单次循环采购数量
                BigDecimal loopNum = BigDecimal.ZERO;

                BigDecimal quantityReceived = new BigDecimal(String.valueOf(invoiceDetail.get("quantity")));

                BigDecimal receivedNum = doneInvoiceNum;

                for (Map<String, Object> memberGoods : memberGoodsList) {

                    BigDecimal num = new BigDecimal(String.valueOf(memberGoods.get("num")));
                    purchaseNum = purchaseNum.add(num);

                    if (receivedNum.compareTo(loopNum = loopNum.add(num)) == 1) {
                        continue;
                    }

                    BigDecimal residueNum = loopNum.subtract(receivedNum);

                    if (quantityReceived.compareTo(residueNum) <= 0) {

                        BigDecimal prePrice = new BigDecimal(String.valueOf(memberGoods.get("pre_price")));
                        costAmount = quantityReceived.multiply(prePrice).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP).add(costAmount);
                        receivedNum = residueNum.add(receivedNum);
                        quantityReceived = quantityReceived.subtract(residueNum);
                    }
                }
                purchaseTransferPurchasePretaxAmount = costAmount.add(purchaseTransferPurchasePretaxAmount);
            }

            if (null == isTransfer || isTransfer) {
                platformDoesNotIncludeTaxSalesAmount = amount.add(platformDoesNotIncludeTaxSalesAmount);
            }

            vendorOrderIdList.add(String.valueOf(trade.get("vendor_order_id")));
        }


        // purchase_organization_id 获取采购方组织信息
        List<SelectorFormat> purchaseSelector = new ArrayList<>();
        if (null != invoiceApply.getPurchase_organization_id()) {
            purchaseSelector = JsonParseObject.parseObject(String.valueOf(invoiceApplyData.get("purchase_organization_id")), SelectorFormat.class);
        }
        log.info("purchaseSelector :{}", purchaseSelector);

        Map<String, Object> purchaseOrg = JdbcTemplateUtils.builder(AppConst.SYSTEM_MANAGEMENT, ModelConst.T_ORGANIZATION)
                .eq("id", purchaseSelector.get(0).getId()).selectField("*").queryForMap();

        String parentName = "";
        if (null != purchaseOrg.get("parent_id")) {
            parentName = String.valueOf(purchaseOrg.get("parent_name"));
        }

        //获取 当前会话 部门信息
        SelectorFormat currentDepartment = boValidatedAndFormatService.getCurrentDepartment();

        Map<String, Object> currentDepart = JdbcTemplateUtils.builder(AppConst.SYSTEM_MANAGEMENT, ModelConst.T_DEPARTMENT)
                .eq("id", currentDepartment.getId()).selectField("*").queryForMap();


        //既有转采 又有非转采
        Boolean isTransferPurchaseAndPlatform = transferPurchase.size() > 1 && transferPurchase.contains(true);

        //转采
        Boolean isTransfer = transferPurchase.contains(true);

        //红票数据
        Map<String, Object> offsetInvoice = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).eq("id", invoiceApply.getOffset_id()).selectField("*").queryForMap();

        Assert.notNull(offsetInvoice, "未获取到对应的 货物蓝字发票  ！！！");

        String number = String.valueOf(offsetInvoice.get("number"));


        SelectorFormat purchaseOrganizationId = invoiceApply.getPurchase_organization_id();
        SelectorFormat saleOrganizationId = invoiceApply.getSale_organization_id();
        String accountName = PlatformConst.getPlatformOrganizationName(purchaseOrganizationId.getId(), saleOrganizationId.getId());

        boolean flag = PlatformConst.PLATFORM_ORGANIZATION_IDS.contains(purchaseOrganizationId.getId()) && InvoiceBusinessType.valueOf(invoiceApply.getBusiness_type()).equals(InvoiceBusinessType.RedProduct);

        KingDeeRedInvoiceApply kingDeeRedInvoiceApply = new KingDeeRedInvoiceApply();
        kingDeeRedInvoiceApply.setId(invoiceApply.getId());
        kingDeeRedInvoiceApply.setInvoiceTime(invoiceApply.getDate());
        kingDeeRedInvoiceApply.setApplyOrganizationId(invoiceApply.getSale_organization_id().getId());
        kingDeeRedInvoiceApply.setType(convertInvoiceType(invoiceApply.getType()));
        kingDeeRedInvoiceApply.setTaxPayable(invoiceApply.getTax_amount());
        kingDeeRedInvoiceApply.setPretaxAmount(invoiceApply.getPrice_amount());
        kingDeeRedInvoiceApply.setAmount(invoiceApply.getTotal());
        kingDeeRedInvoiceApply.setNumber(invoiceApply.getNumber());
        kingDeeRedInvoiceApply.setApplyOrganizationCompanyName(invoiceApply.getSale_organization_name());
        kingDeeRedInvoiceApply.setConfirmOrganizationCompanyName(invoiceApply.getPurchase_organization_name());
        kingDeeRedInvoiceApply.setDepartmentNumber(String.valueOf(currentDepart.get("number")));
        kingDeeRedInvoiceApply.setOrgId(String.valueOf(purchaseOrg.get(("id"))));
        kingDeeRedInvoiceApply.setParentName(parentName);
        kingDeeRedInvoiceApply.setTaxRate(new BigDecimal(String.valueOf(extendsAttr.getTaxRate())));
        kingDeeRedInvoiceApply.setPurchaseTransferPurchasePretaxAmount(purchaseTransferPurchasePretaxAmount);
        kingDeeRedInvoiceApply.setSaleTransferPurchasePretaxAmount(saleTransferPurchasePretaxAmount);
        kingDeeRedInvoiceApply.setPlatformDoesNotIncludeTaxSalesAmount(platformDoesNotIncludeTaxSalesAmount);
        kingDeeRedInvoiceApply.setIsTransferPurchaseAndPlatform(isTransferPurchaseAndPlatform);
        kingDeeRedInvoiceApply.setIsTransfer(isTransfer);
        kingDeeRedInvoiceApply.setNumbers(number);
        kingDeeRedInvoiceApply.setIsRed(!flag);
        kingDeeRedInvoiceApply.setKingdeeCode(kingdeeCode);
        kingDeeRedInvoiceApply.setVoucherId(String.join(",", vendorOrderIdList));
        kingDeeRedInvoiceApply.setPurchaseName(invoiceApply.getPurchase_name());
        kingDeeRedInvoiceApply.setAccountName(accountName);
        log.info("createOrUpdateRedInvoiceVoucher  End of  logic processing <<<");

        return kingDeeRedInvoiceApply;
    }


    public List<InvoiceApply> getInvoiceApplyListByIds(List<String> businessList) {
        log.info("getInvoiceApplyListByIds  request:{}", businessList);

        List<InvoiceApply> invoiceApplyList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField("*")
                .in("id", businessList).queryForPOJOList(InvoiceApply.class);

        Assert.isTrue(null != invoiceApplyList && invoiceApplyList.size() > 0, "未找到 发票申请单数据!!! ");

        invoiceApplyList.stream().forEach(e -> {
            //账套名称赋值
            SelectorFormat purchaseOrganizationId = e.getPurchase_organization_id();
            SelectorFormat saleOrganizationId = e.getSale_organization_id();
            String accountName = PlatformConst.getPlatformOrganizationName(purchaseOrganizationId.getId(), saleOrganizationId.getId());
            e.setAccount_name(accountName);

        });
        log.info("getInvoiceApplyListByIds  End of  logic processing <<<");

        return invoiceApplyList;
    }


    /**
     * 获取 服务费发票的账单维度明细 与 对应的结算核销的货物发票号码
     *
     * @param id 发票申请单 id
     * @return
     */
    public List<BillFeeDto> getServiceInvoiceAndGoodsInvoice(String id) {
        log.info("getServiceInvoiceAndGoodsInvoice  request:{}", id);

        //根据发票申请单 id 获取对应的 发票明细账单
        List<InvoiceDetailBill> invoiceDetailBillList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_DETAIL_BILL).eq("invoice_apply_id", id)
                .selectField("*").queryForPOJOList(InvoiceDetailBill.class);

        Assert.isTrue(null != invoiceDetailBillList && invoiceDetailBillList.size() > 0, "未找到 发票申请单明细账单!!! ");

        List<String> billIdLists = invoiceDetailBillList.stream().map(e -> e.getBill_id()).collect(Collectors.toList());

        List<Bill> billList = JdbcTemplateUtils.builder(ModelConst.T_BILL).in("id", billIdLists).selectField("*").queryForPOJOList(Bill.class);

        Assert.isTrue(null != billList && billList.size() > 0, "未找到  对应 账单数据!!! ");

        List<String> referenceIds = billList.stream().map(e -> e.getReference_id()).collect(Collectors.toList());


//        SELECT detail.ID ID,detail.total settleTotal,settle.payment_time settleTime,detail.settle_id settleId,invoice.NUMBER goodsInvoiceNumber FROM t_settle_detail detail
//        LEFT JOIN t_settle settle ON settle.ID = detail.settle_id
//        LEFT JOIN t_invoice_apply invoice ON invoice.ID = detail.invoice_apply_id
//        WHERE  detail.ID IN ( :settleDetailIds )

        String invoiceApplyTable = JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_APPLY);
        String settleTable = JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE);
        String settleDetailTable = JdbcTemplateUtils.getTableName(ModelConst.T_SETTLE_DETAIL);

        log.info("数据库名称  invoiceApplyTable:{},settleTable:{},settleDetailTable:{}", invoiceApplyTable, settleTable, settleDetailTable);

        StringBuilder sbStr = new StringBuilder();
        sbStr.append("SELECT detail.id ,detail.total ,settle.payment_time ,detail.settle_id ,invoice.number  FROM ");
        sbStr.append(settleDetailTable);
        sbStr.append(" AS detail LEFT JOIN ");
        sbStr.append(settleTable);
        sbStr.append(" AS settle ON settle.id = detail.settle_id LEFT JOIN ");
        sbStr.append(invoiceApplyTable);
        sbStr.append(" AS invoice ON invoice.id = detail.invoice_apply_id ");
        sbStr.append(" WHERE  detail.id IN ( :settleDetailIds ) ");
        String sql = sbStr.toString();
        log.info("根据来源id获取对应结算信息 执行SQL :{}", sql);
        Map<String, Object> paramM = new HashMap<>();
        paramM.put("settleDetailIds", referenceIds);
        List<Map<String, Object>> settleInfo = JdbcTemplateUtils.queryForList(sql, paramM);

        Assert.isTrue(null != settleInfo && settleInfo.size() > 0, "未找到  对应 结算信息 ！！ ");

        List<BillFeeDto> billFeeDtoList = new ArrayList<>();
        for (Map<String, Object> settle : settleInfo) {

            List<Bill> filterBill = billList.stream().filter(e -> e.getReference_id().equals(String.valueOf(settle.get("id")))).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(filterBill)) {
                continue;
            }
            for (Bill invoiceBill : filterBill) {
                BillFeeDto billFeeDto = new BillFeeDto();
                billFeeDto.setType(BillType.valueOf(invoiceBill.getType()));
                billFeeDto.setGoods_invoice_number(String.valueOf(settle.get("number")));
                billFeeDto.setTotal(invoiceBill.getTotal());
                billFeeDto.setTax_rate(invoiceBill.getTax_rate());
                billFeeDtoList.add(billFeeDto);
            }

        }
        log.info("getServiceInvoiceAndGoodsInvoice  End of  logic processing <<<");

        return billFeeDtoList;
    }

    public InvoiceApply getInvoiceApply(String businessId) {
        log.info("getInvoiceApply  request:{}", businessId);

        InvoiceApply invoiceApply = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).eq("id", businessId)
                .selectField("*").queryForPOJO(InvoiceApply.class);

        Assert.notNull(invoiceApply, "未获取到对应的 发票申请单数据  ！！！");

        //账套名称赋值
        SelectorFormat purchaseOrganizationId = invoiceApply.getPurchase_organization_id();
        SelectorFormat saleOrganizationId = invoiceApply.getSale_organization_id();
        String accountName = PlatformConst.getPlatformOrganizationName(purchaseOrganizationId.getId(), saleOrganizationId.getId());
        invoiceApply.setAccount_name(accountName);
        log.info("getInvoiceApply  End of  logic processing <<<");

        return invoiceApply;
    }

    public KingDeeInvoiceApplyTypeEnum convertInvoiceType(String type) {
        KingDeeInvoiceApplyTypeEnum typeEnum;
        if (type == InvoiceType.VatOrdinary.name()) {
            typeEnum = KingDeeInvoiceApplyTypeEnum.VAT_ORDINARY;
        } else if (type == InvoiceType.VatSpecial.name()) {
            typeEnum = KingDeeInvoiceApplyTypeEnum.VAT_SPECIAL;
        } else if (type == InvoiceType.VatOrdinaryElectronic.name()) {
            typeEnum = KingDeeInvoiceApplyTypeEnum.VAT_EL_TICKET;
        } else {
            //TODO 李国祥 新版财务增加了商城个人发票，是否在凭证增加该类型
            typeEnum = KingDeeInvoiceApplyTypeEnum.NO_INVOICING;
        }
        return typeEnum;
    }


}
